package com.group9.handinhand.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
 * Class for dao
 *
 */
@Repository
@SuppressWarnings("unchecked")
public class BaseDaoImpl implements BaseDao {
	
	@Autowired
	private SessionFactory sessionFactory;
	/**
	 * gets session factory
	 * @return
	 */
	private SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	/**
	 * gets session
	 * @return
	 */
	private Session getSession() {
		Session sess = getSessionFactory().getCurrentSession();
		if (sess == null) {
			sess = getSessionFactory().openSession();
		}
		return sess;
	}
	
	@Override
    public Serializable save(Object transientInstance) {
		getSession().setFlushMode(FlushMode.AUTO);
		return getSession().save(transientInstance);
    }
	/**
	 * updates instance on the session
	 */
	@Override
	public void update(Object instance) {
		getSession().update(instance);
	}
	/**
	 * merges the instance with session
	 */
	@Override
	public void merge(Object instance) {
		getSession().merge(instance);
	}
	/**
	 * deletes instance on this session
	 */
	@Override
	public void delete(Object instance){
		getSession().delete(instance);
	}
	/**
	 * returns all the list of all entities
	 */
	@Override
	public <T> List<T> findAll(Class<T> entityClass) {
		return getSession().createCriteria(entityClass).list();
	}
	/**
	 * returns all the list of all entities according to id
	 */
	@Override
	public <T> Object findById(Class<T> entityClass, Serializable id) {
		return (T) getSession().get(entityClass, id);
    }
	/**
	 * returns all the list of all entities according to criteria
	 */
	@Override
    public <T> List<T> findEntityByProperty(Class<T> entityClass, String property, Object value) {
		Criteria criteria = getSession().createCriteria(entityClass);
		criteria.add(Restrictions.eq(property, value));
		return criteria.list();
    }
	/**
	 * returns all the list of all entities according to criteria
	 */
	@Override
    public <T> List<T> findEntityByPropertyOrderBy(Class<T> entityClass, String property, Object value) {
		Criteria criteria = getSession().createCriteria(entityClass);
		criteria.add(Restrictions.eq(property, value));
		return criteria.list();
    } 
	/**
	 * returns all the list of all entities according to criteria by unique result
	 */
	@Override
	public <T> T findEntityByPropertyUnique(Class<T> entityClass, String property, Object value) {
		Criteria criteria = getSession().createCriteria(entityClass);
		criteria.add(Restrictions.eq(property, value));
		return (T) criteria.uniqueResult();
	}
	/**
	 * returns all the list of all entities according to criteria
	 */
	@Override
   public <T> T findEntityByPropertyUnique(Class<T> cls, String[] properties, Object[] values) {
		Criteria criteria = getSession().createCriteria(cls);
		int k = Math.min(properties.length, values.length);
		for (int i = 0; i < k; i++) {
		    criteria.add(Restrictions.eq(properties[i], values[i]));
		}
		return (T) criteria.uniqueResult();
	    }
	/**
	 * returns query list 
	 */
	@Override
	public <T> List<T> executeQueryString(String queryString, String property, Object value) {
		Query query = getSession().createQuery(queryString);
		query.setParameter(property, value);
		return query.list();
	}
	/**
	 * returns query list 
	 */
	@Override
	public <T> List<T> executeQueryString(String queryString, String[] properties, Object[] values) {
		Query query = getSession().createQuery(queryString);
		int k = Math.min(properties.length, values.length);
		for (int i = 0; i < k; i++) {
			query.setParameter(properties[i], values[i]);
		}
		return (List<T>)query.list();
	}
	/**
	 * returns query list
	 */
	@Override
	public <T> T executeQueryStringForObject(String queryString, String[] properties, Object[] values) {
		Query query = getSession().createQuery(queryString);
		int k = Math.min(properties.length, values.length);
		for (int i = 0; i < k; i++) {
			query.setParameter(properties[i], values[i]);
		}
		return (T) query.uniqueResult();
	}

}
